package com.ajz.common.web;

import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.ui.Model;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import com.ajz.common.dto.PagingVO;
import com.ajz.common.dto.Result;
import com.ajz.common.entity.BaseEntity;
import com.ajz.common.exception.BusinessException;
import com.ajz.common.service.IBaseService;
import com.ajz.common.utils.Collections3;
import com.ajz.common.utils.Exceptions;
import com.ajz.common.utils.StringUtils;
import com.ajz.security.utils.SecurityUtils;
import com.google.common.base.Joiner;
import com.google.common.collect.Lists;



/**
 * 控制器基类
 * @author xyj
 * @create 2017年2月9日 下午3:54:34
 * @param <T>
 * @param <ID>
 */
public abstract class BaseController<T extends BaseEntity<?>, ID extends Serializable> extends RoleBaseController {

	protected Logger logger = LoggerFactory.getLogger(this.getClass());

	public static final String SEARCH_PARAM_PREFIX = "search_";

	public static final String LIST_PAGE = "{entityInstanceName}-list";

	public static final String ADD_PAGE = "{entityInstanceName}-add";

	public static final String EDIT_PAGE = "{entityInstanceName}-edit";

	public static final String VIEW_PAGE = "{entityInstanceName}-view";

	@Autowired
	protected IBaseService<T, ID> baseService;

	protected Class<T> entityClass;

	protected String baseViewPath;

	protected String entityInstanceName;

	@SuppressWarnings("unchecked")
	public BaseController() {
		Annotation annotation = AnnotationUtils.findAnnotation(this.getClass(), RequestMapping.class);
		baseViewPath = ((String[]) AnnotationUtils.getValue(annotation, "value"))[0].substring(1);

		Type t = getClass().getGenericSuperclass();
		if (t instanceof ParameterizedType) {
			Type[] p = ((ParameterizedType) t).getActualTypeArguments();
			entityClass = (Class<T>) p[0];
		}
		entityInstanceName = StringUtils.toLowerCaseFirstOne(entityClass.getSimpleName());
	}

	/**
	 * 列表页面
	 * 
	 * @return
	 */
	@RequestMapping(value = "/index")
	public String index() {
		return list();
	}

	/**
	 * 列表页面
	 * 
	 * @return
	 */
	@RequestMapping(value = "/list")
	public String list() {
		if (!SecurityUtils.hasRole(this.getQueryRole())) {
			return DENY_PAGE;
		}
		
		String page = getPagePath(LIST_PAGE);
		return page;
	}

	/**
	 * 新增页面
	 * 
	 * @return
	 */
	@RequestMapping(value = "/add")
	public String add(ModelMap model) {

		if (!SecurityUtils.hasRole(this.getAddRole())) {
			return DENY_PAGE;
		}

		String page = getPagePath(ADD_PAGE);
		return page;
	}

	/**
	 * 编辑页面
	 * 
	 * @return
	 */
	@RequestMapping(value = "/edit/{id}")
	public String edit(ModelMap model) {

		if (!SecurityUtils.hasRole(this.getEditRole())) {
			return DENY_PAGE;
		}

		String page = getPagePath(EDIT_PAGE);
		return page;
	}

	/**
	 * 查看页面
	 * 
	 * @return
	 */
	@RequestMapping(value = "/view/{id}")
	public String view(ModelMap model) {

		if (!SecurityUtils.hasRole(this.getQueryRole())) {
			return DENY_PAGE;
		}

		String page = getPagePath(VIEW_PAGE);
		return page;
	}

	/**
	 * 计算页面路径
	 * 
	 * @param pageType
	 * @return
	 */
	protected String getPagePath(String pageType) {
		String view = String.format("%s/%s", baseViewPath,
				pageType.replaceAll("\\{entityInstanceName\\}", StringUtils.camelToHyphen(entityInstanceName)));
		return view;
	}

	/**
	 * 分页查询
	 * @param pageNo
	 * @param pageSize
	 * @param request
	 * @return
	 */
	@RequestMapping(value = "/query")
	@ResponseBody
	public Result query(Integer pageNo, Integer pageSize, HttpServletRequest request) {
		try {
			if (!SecurityUtils.hasRole(this.getQueryRole())) {
				return Result.denyResult();
			}

			if (pageNo == null) {
				pageNo = 1;
			}

			if (pageSize == null) {
				pageSize = 10;
			}

			pageNo = pageNo - 1;
			PageRequest PageRequest = new PageRequest(pageNo, pageSize);
			Map<String, Object> searchParams = Servlets.getParametersStartingWith(request, SEARCH_PARAM_PREFIX);
			// 统一过滤数据权限
			filterDataPermission(searchParams);
			Page<T> page = baseService.findPage(PageRequest, searchParams);

			return Result.successResult(page);
		} catch (Exception e) {
			String msg = Exceptions.getMessage(e);
			logger.error(msg, e);
			return Result.errorResult(msg);
		}
	}

	/**
	 * 查询所有用户的全部数据
	 * @return
	 */
	@RequestMapping(value = "/findAll")
	@ResponseBody
	public Result findAll(HttpServletRequest request) {
		try {
			if (!SecurityUtils.hasRole(this.getQueryRole())) {
				return Result.denyResult();
			}
			List<T> list = baseService.findAll();
			return Result.successResult(list);
		} catch (Exception e) {
			String msg = Exceptions.getMessage(e);
			logger.error(msg, e);
			return Result.errorResult(msg);
		}
	}
	/**
	 * 查询当前用户全部数据
	 * @return
	 */
	@RequestMapping(value = "/findThisAll")
	@ResponseBody
	public Result findThisAll(HttpServletRequest request) {
		try {
			if (!SecurityUtils.hasRole(this.getQueryRole())) {
				return Result.denyResult();
			}
			Map<String, Object> searchParams = Servlets.getParametersStartingWith(request, SEARCH_PARAM_PREFIX);
			// 统一过滤数据权限
			filterDataPermission(searchParams);
			
			List<T> list = baseService.findThisAll(searchParams);
			return Result.successResult(list);
		} catch (Exception e) {
			String msg = Exceptions.getMessage(e);
			logger.error(msg, e);
			return Result.errorResult(msg);
		}
	}

	/**
	 * 根据id获取单条记录
	 * @param id
	 * @return
	 */
	@RequestMapping(value = "/get/{id}")
	@ResponseBody
	public Result get(@PathVariable("id") ID id) {
		try {
			if (!SecurityUtils.hasRole(this.getQueryRole())) {
				return Result.denyResult();
			}

			T entity = baseService.get(id);
			return Result.successResult(entity);
		} catch (Exception e) {
			String msg = Exceptions.getMessage(e);
			logger.error(msg, e);
			return Result.errorResult(msg);
		}
	}

	/**
	 * 根据id删除单条记录
	 * @param id
	 * @return
	 */
	@RequestMapping(value = "/delete/{id}")
	@ResponseBody
	public Result delete(@PathVariable("id") ID id) {
		try {
			if (!SecurityUtils.hasRole(this.getDeleteRole())) {
				return Result.denyResult();
			}

			baseService.delete(id);
			return Result.successResult();
		} catch (Exception e) {
			String msg = Exceptions.getMessage(e);
			logger.error(msg, e);
			return Result.errorResult(msg);
		}
	}

	/**
	 * 根据id串批量删除
	 * @param idStr
	 * @return
	 */
	@SuppressWarnings("unchecked")
	@RequestMapping(value = "/deletes/{idStr}")
	@ResponseBody
	public Result deletes(@PathVariable("idStr") String idStr) {
		try {

			if (!SecurityUtils.hasRole(this.getBatchDeleteRole())) {
				return Result.denyResult();
			}

			ID[] ids = (ID[]) idStr.split(",");
			baseService.delete(ids);

			return Result.successResult();
		} catch (Exception e) {
			String msg = Exceptions.getMessage(e);
			logger.error(msg, e);
			return Result.errorResult(msg);
		}
	}

	/**
	 * 根据id串批量删除
	 * @param ids
	 * @return
	 */
	@RequestMapping(value = "/deletes")
	@ResponseBody
	public Result deleteBatch(@RequestParam(value = "ids[]") ID[] ids) {
		try {
			if (!SecurityUtils.hasRole(this.getBatchDeleteRole())) {
				return Result.denyResult();
			}

			if (ids == null || ids.length == 0) {
				throw new BusinessException("参数为空");
			}

			baseService.delete(ids);

			return Result.successResult();
		} catch (Exception e) {
			String msg = Exceptions.getMessage(e);
			logger.error(msg, e);
			return Result.errorResult(msg);
		}
	}

	/**
	 * 新增
	 * @param entity
	 * @return
	 */
	@RequestMapping(value = "/save")
	@ResponseBody
	public Result save(/* @RequestBody */T entity) {
		try {
			if (!SecurityUtils.hasRole(this.getAddRole())) {
				return Result.denyResult();
			}

			baseService.save(entity);

			return Result.successResult();
		} catch (Exception e) {
			String msg = Exceptions.getMessage(e);
			logger.error(msg, e);
			return Result.errorResult(msg);
		}
	}
	/**
	 * 修改
	 * @param entity
	 * @return
	 */
	@RequestMapping(value = "/update")
	@ResponseBody
	public Result update(/* @RequestBody */@ModelAttribute("entity") T entity) {
		try {
			if (!SecurityUtils.hasRole(this.getEditRole())) {
				return Result.denyResult();
			}
			baseService.update(entity);
			return Result.successResult();
		} catch (Exception e) {
			String msg = Exceptions.getMessage(e);
			logger.error(msg, e);
			return Result.errorResult(msg);
		}
	}

	/**
	 * 新增或修改
	 * @param entity
	 * @return
	 */
	@RequestMapping(value = "/saveOrUpdate")
	@ResponseBody
	public Result saveOrUpdate(@RequestBody T entity) {
		try {

			if (!SecurityUtils.hasRole(this.getAddRole()) && !SecurityUtils.hasRole(this.getEditRole())) {
				return Result.denyResult();
			}

			baseService.save(entity);

			return Result.successResult();
		} catch (Exception e) {
			String msg = Exceptions.getMessage(e);
			logger.error(msg, e);
			return Result.errorResult(msg);
		}
	}

	/**
	 * 所有RequestMapping方法调用前的Model准备方法, 实现Struts2
	 * Preparable二次部分绑定的效果,先根据form的id从数据库查出Task对象,再把Form提交的内容绑定到该对象上。
	 * 因为仅update()方法的form中有id属性，因此仅在update时实际执行.
	 */
	@ModelAttribute
	public void getEntity(@RequestParam(value = "id", defaultValue = "-1") ID id, Model model) {
		if (!String.valueOf(id).equals("-1")) {
			model.addAttribute("entity", baseService.get(id));
		}
	}

	@InitBinder  
	public void initBinder(WebDataBinder binder) {  
	    // 设置List的最大长度  
	    binder.setAutoGrowCollectionLimit(10000);  
	} 
	
	
	
	/* 分页查询
	 * @param pageNo
	 * @param pageSize
	 * @param request
	 * @return
	 */
	@RequestMapping(value = "/queryPage")
	@ResponseBody
	public Result queryPage(Integer pageNo, Integer pageSize, HttpServletRequest request) {
		try {
			if (!SecurityUtils.hasRole(this.getQueryRole())) {
				return Result.denyResult();
			}
			if (pageNo == null) {
				pageNo = 1;
			}

			if (pageSize == null) {
				pageSize = 10;
			}
			//Sort a= new Sort(orders);
			PageRequest PageRequest = new PageRequest(pageNo - 1, pageSize);
			Map<String, Object> searchParams = Servlets.getParametersStartingWith(request, SEARCH_PARAM_PREFIX);
//			Sort sort = SearchFilter.getSorts(searchParams);
//			if(sort!=null){
//				 PageRequest = new PageRequest(pageNo - 1, pageSize,sort);
//			}
			// 统一过滤数据权限
			filterDataPermission(searchParams);
			Page<T> page = baseService.findPage(PageRequest, searchParams);
			PagingVO paging = new PagingVO(page.getContent(),
					(int)page.getTotalElements(), pageNo, pageSize);
			return Result.successResult(paging);
		} catch (Exception e) {
			String msg = Exceptions.getMessage(e);
			logger.error(msg, e);
			return Result.errorResult(msg);
		}
	}
	
	
	// 数据权限处理
	protected void filterDataPermission(Map<String, Object> searchParams) {
		if (SecurityUtils.needCheckDataPermission(this.entityClass)) {
			filterDataPermissionForce(searchParams);
		}
	}

	protected void filterDataPermissionForce(Map<String, Object> searchParams) {
		String checkField = SecurityUtils.getDataPermissionCheckField(this.entityClass);
		
		String conditionKey = String.format("IN_%s", checkField);
		
		String valueStr = (String)searchParams.get(conditionKey);
		if (StringUtils.isNotEmpty(valueStr)) {
			List<String> values = Lists.newArrayList(valueStr.split(","));
			
			List<String> dataPermissions = SecurityUtils.getDataPermissions();
			if (!Collections3.isEmpty(dataPermissions)) {
				values.retainAll(dataPermissions); 
			}
			searchParams.put(conditionKey, Joiner.on(",").join(values));
		} else {
			searchParams.put(conditionKey, SecurityUtils.getDataPermissionStr());
		}
	}
	
}
